package org.pi.common.plot.figures

trait BaseFigure extends Figure with org.pi.common.observerpattern.ObservableImpl {
	protected var elements = new scala.collection.mutable.ListBuffer[(Float, Float, Float, Float, org.pi.common.plot.axes.Axes)]()
	private var figureWidth: Int = 320
	private var figureHeight: Int = 240
	private val subplots = new scala.collection.mutable.HashMap[(Int,Int,Int),Int]()
	private var currentAxesIndex: Int = 0

	/** get the axes for a given index */
	def getAxes(index: Int) : org.pi.common.plot.axes.Axes = elements(index)._5
	/** get the axes for a given location in the figure (in screen pixels) */
	def getAxesIndex(x: Float, y: Float) : Int = {
		var result = -1
		var k = 0
		var (x1,y1) = (x/figureWidth.toFloat,y/figureHeight.toFloat)
		while (k < elements.length) {
			//println("searching "+(x1,y1)+" in "+elements(k))
			if (x1>=elements(k)._1 && x1<=elements(k)._3 && y1>=elements(k)._2 && y1<=elements(k)._4) {
				result = k
			}
			k += 1
		}
		result
	}
	
	/** get the axes and the position within the axes (in axes coordinates) for a given location in the figure (in screen pixels) */
	def getPositionForAxes(x1: Float, y1: Float, index: Int) : (Float, Float) = {
		elements(index)._5.getPositionInAxesForGivenPointOnScreen(x1,y1)
	}

	/** get the axes size in the figure (in screen pixels) */
	def getAxesSizeInPixels(index: Int) : (Float, Float) = {
		val w = (elements(index)._3-elements(index)._1)
		val h = (elements(index)._4-elements(index)._2)
		(w*figureWidth.toFloat, h*figureHeight.toFloat)
	}
  
  override def clear {
	elements.clear
	subplots.clear
	notifyObservers()
  }
  override def addAxes(x1: Float, y1: Float, x2: Float, y2: Float, axes: org.pi.common.plot.axes.Axes) {
	elements += ((x1,y1,x2,y2,axes))
	if (axes!=null) axes.addObserver(this)
	notifyObservers()
  }
  
  override def setAxes(index: Int, axes: org.pi.common.plot.axes.Axes) {
	  //TODO remove this from old observable/axes
	elements(index) = (elements(index)._1, elements(index)._2, elements(index)._3, elements(index)._4, axes);
    if (axes!=null) axes.addObserver(this)
	notifyObservers()
  }

  override def setCurrentAxes(axes: org.pi.common.plot.axes.Axes) {
	  if (currentAxesIndex>=elements.length) { 
	 	  subplot(1,1,0) 
	  }
	  setAxes(currentAxesIndex, axes)
  }

  override def getCurrentAxes(): org.pi.common.plot.axes.Axes = {
	if (currentAxesIndex>=elements.length) {
	  setCurrentAxes(new org.pi.common.plot.axes.SimpleAxes())
	}
	else if (elements(currentAxesIndex)._5==null) {
	  setCurrentAxes(new org.pi.common.plot.axes.SimpleAxes())
	}
    elements(currentAxesIndex)._5
  }

  override def getAxesForSubplot(xn: Int, yn: Int, index: Int): org.pi.common.plot.axes.Axes = {
	if (subplots.contains( (xn,yn,index) )) elements(subplots( (xn,yn,index) ))._5
	else throw new Error("unused/undefined subplot!")
  }
  
  override def subplot(xn: Int, yn: Int, index: Int): Int = {
	if (subplots.contains( (xn,yn,index) )) {
	  currentAxesIndex = subplots( (xn,yn,index) )
	}
	else {
  	  val xi = index % xn
	  val yi = index / xn
 	
	  val x1 = xi.toFloat / xn.toFloat
 	  val y1 = yi.toFloat / yn.toFloat 
 	  val x2 = (xi.toFloat+1.0f) / xn.toFloat 
 	  val y2 = (yi.toFloat+1.0f) / yn.toFloat 
	
	  //println(":"+x1+","+y1+"--"+x2+","+y2)

  	  currentAxesIndex = elements.length
  	  subplots( (xn,yn,index) ) = currentAxesIndex 

  	  addAxes(x1,y1,x2,y2,null)
	}
	currentAxesIndex
  }
  
  override def paintFigure(graphics: java.awt.Graphics2D) {
	val bounds = graphics.getClipBounds
    if (bounds==null) throw new Error("unexpected: no clip set.")
	figureWidth = bounds.getWidth.toInt
    figureHeight = bounds.getHeight.toInt
    //if (bounds.getX()!=0 || bounds.getY()!=0) throw new Error("unexpected: clip does not start at (0,0).")

	elements.foreach( tuple => {
	  val x1 = tuple._1 
	  val y1 = tuple._2 
	  val x2 = tuple._3 
	  val y2 = tuple._4 
	  val axes = tuple._5
	  graphics.setClip( 
	    bounds.x + (x1*bounds.width.toFloat).toInt, 
	    bounds.y + (y1*bounds.height.toFloat).toInt,
	    (bounds.width.toFloat * (x2-x1) ).toInt,
	    (bounds.height.toFloat * (y2-y1) ).toInt 
	  )
	  if (axes!=null) axes.paint(graphics)
	})
	graphics.setClip(null) // clear clip, see javadoc (docu for getClipBounds)
  }
  override def notifiedByObservable(obs: org.pi.common.observerpattern.Observable) {
	notifyObservers()
  }

  override def saveAs(filename: String) {
	  saveAs(filename, figureWidth, figureHeight)
  }

  override def saveAs(filename: String, width: Int, height: Int) {
    val bImage = new java.awt.image.BufferedImage(width,height,java.awt.image.BufferedImage.TYPE_3BYTE_BGR);
    val graphics = bImage.getGraphics().asInstanceOf[java.awt.Graphics2D]
    graphics.setClip(0,0,width,height)
    graphics.setColor(java.awt.Color.white)
    graphics.fillRect(0,0,width,height)
    graphics.setColor(java.awt.Color.black)
	paintFigure(graphics)
    val format = filename.substring(filename.lastIndexOf(".")+1)
    javax.imageio.ImageIO.write(bImage,format,new java.io.File(filename));
  }

}
